﻿using System;
using System.Collections.Generic;
using System.Web;
using DotNetOpenAuth.OAuth2;
using System.Web.Mvc;
using System.Net;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.IO;
using System.Text;
using ImaginaryDevelopmentMvc3.App.Web;
using System.Diagnostics;
using System.Diagnostics.Contracts;

namespace ImaginaryDevelopmentMvc3.App.Auth
{
    public class WindowsLive : IOauthClient
    {

        public static string GetCallbackUri(HttpContextBase context)
        {


            return string.Format("{0}://{1}{2}", context.Request.RequestContext.HttpContext.Request.Url.Scheme, context.Request.RequestContext.HttpContext.Request.Url.Authority,
               UrlHelper.GenerateContentUrl("~/Auth/Callback?type=wl", context));

        }
        //private const IEnumerable<string> defaultScopes = new[] { "wl.signin%20wl.basic" };

        

        #region IOauthClient Members

        public void Authenticate(Uri callback)
        {
            var wl = new WindowsLiveClient();

            wl.RequestUserAuthorization(returnTo: callback);

        }
        public string Token { get; private set; }
        public WindowsLiveUser WindowsLiveUser { get; private set; }
        public string VerifyUrl { get; private set; }
        public OpenIdentity Verify()
        {

            var wl = new WindowsLiveClient();
            if (wl.ClientSecret.IsNullOrEmpty())
                return null;
            if (wl.ClientIdentifier.IsNullOrEmpty())
                return null;
            IAuthorizationState authorization = wl.ProcessUserAuthorization();
            Trace.WriteLine("Token:"+authorization.AccessToken);
            Trace.WriteLine("AuthorizationType:"+authorization.GetType().FullName);
            Trace.WriteLine("Scopes:" + authorization.Scope.Aggregate(","));
            var Token = authorization.AccessToken;
            if (Token == null)
                return null;


            var context = new HttpContextWrapper(HttpContext.Current);
            var callback = HttpUtility.UrlEncode(WindowsLive.GetCallbackUri(context));
            Trace.WriteLine("VerifyCallback will be " + callback);
            
            // VerifyUrl = string.Format("https://oauth.live.com/token?client_id={0}&redirect_uri={1}&client_secret={2}&code={3}&grant_type=authorization_code",
            //    App.Configuration.WindowsLiveClientId, callback, App.Configuration.WindowsLiveClientSecret,  Uri.EscapeDataString(Token));
            // if (VerifyUrl == null)
            //    return null;
            //Trace.WriteLine("VerifyUrl = "+VerifyUrl);
            // var request = WebRequest.Create(VerifyUrl);
            var baseInfoUri = "https://apis.live.net/v5.0/";
            var request = WebRequest.Create(baseInfoUri+"me?access_token="+Uri.EscapeDataString(Token));
            using (var response = request.GetResponse())
            {
                Trace.WriteLine("GetResponse success");
                using (var responseStream = response.GetResponseStream())
                {
                    Trace.WriteLine("GetReponseStream success");
                     WindowsLiveUser = WindowsLiveUser.Deserialize(responseStream);
                     Trace.WriteLine("Deserialize success");
                     if (WindowsLiveUser != null)
                         Trace.WriteLine(WindowsLiveUser.ToJson());
                     return new OpenIdentity() { Id = WindowsLiveUser.ID, Username = WindowsLiveUser.Name, SiteProvider = "WindowsLive" };
                }
            }
        }

        #endregion
    }
    /// <summary>
    /// http://msdn.microsoft.com/en-us/library/hh243647.aspx
    /// </summary>
    [DataContract]
    public class WindowsLiveVerification
    {
        private static DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(WindowsLiveVerification));

        [DataMember(Name = "access_token")]
        public string AccessToken { get; set; }

        [DataMember(Name = "auth_token")]
        public string AuthToken { get; set; }

        [DataMember(Name = "code")]
        public string Code { get; set; }

        [DataMember(Name = "expires_in")]
        public string ExpiresIn { get; set; }

        [DataMember(Name = "refresh_token")]
        public string Refresh_Token { get; set; }

        [DataMember(Name = "scope")]
        public string Scope { get; set; }

        [DataMember(Name = "state")]
        public string State { get; set; }
        [DataMember(Name = "token_type")]
        public string TokenType { get; set; }

        /// <summary>
        /// Serialize using JsonSerializer
        /// </summary>
        /// <returns></returns>
        public string ToJson()
        {
             System.Diagnostics.Contracts.Contract.Result<string>().IsNotNullOrEmpty();
            using (var writer = new MemoryStream())
            {
                Contract.Ensures(Contract.Result<string>() != null);
                jsonSerializer.WriteObject(writer, this);
                using (var reader = new StreamReader(writer))
                
                return reader.ReadToEnd();
            }
        }

        public static WindowsLiveVerification Deserialize(string json)
        {
            if (String.IsNullOrEmpty(json))
            {
                throw new ArgumentNullException("json");
            }

            return Deserialize(new MemoryStream(Encoding.UTF8.GetBytes(json)));
        }

        public static WindowsLiveVerification Deserialize(Stream jsonStream)
        {
            if (jsonStream == null)
            {
                throw new ArgumentNullException("jsonStream");
            }

            return (WindowsLiveVerification)jsonSerializer.ReadObject(jsonStream);
        }
       
    }

    public class WindowsLiveClient : WebServerClient
    {
        [Flags]
        public enum Scope
        {
            wl_signin,
            wl_basic,
            wl_offline_access
        }
        private static string ScopeValue(Scope scopes = Scope.wl_basic|Scope.wl_signin)
        {
            var scope = new List<string>();
            foreach (Scope value in Enum.GetValues(typeof(Scope)))
                if ((scopes & value) == value)
                    scope.Add(Enum.GetName(typeof(Scope), value).Replace('_', '.'));
            return scope.Aggregate("%20");
        }

        public WindowsLiveClient()
            : base(new AuthorizationServerDescription
            {
                TokenEndpoint = new Uri("https://oauth.live.com/token"),
                AuthorizationEndpoint = new UriBuilder("https://oauth.live.com/authorize").SetQueryParam("Scope", ScopeValue()).Uri
            })
        {

            ClientIdentifier = App.Configuration.WindowsLiveClientId;
            ClientSecret = App.Configuration.WindowsLiveClientSecret;
        }
    }
}